package com.ddpt.permission.controller;

import cn.hutool.extra.servlet.ServletUtil;
import com.lh.center.common.base.session.SessionUser;
import com.lh.center.common.constant.RedisPrefix;
import com.lh.center.common.dto.LoginByPasswordDto;
import com.lh.center.common.enums.LogType;
import com.lh.center.common.enums.MarketingApp;
import com.lh.center.common.exception.CommonException;
import com.lh.center.common.util.AssertUtil;
import com.lh.center.common.util.IpBelongWithinJuheUtil;
import com.lh.center.common.web.CommonWebAutoConfiguration;
import com.lh.center.common.web.session.SessionOperation;
import com.lh.center.merchant.api.dubbo.DubboMerchantInsService;
import com.lh.center.merchant.api.dubbo.DubboMerchantService;
import com.lh.center.merchant.api.entity.Merchant;
import com.lh.center.permission.api.entity.LoginLogEntity;
import com.lh.center.permission.api.entity.MerchantAdminUser;
import com.lh.center.permission.api.session.*;
import com.lh.center.permission.dto.ExternalLoginDto;
import com.lh.center.permission.service.LoginLogService;
import com.lh.center.permission.service.LoginService;
import com.lh.center.permission.service.MerchantAdminUserService;
import com.lh.center.permission.service.login.LoginServiceFactory;
import com.lh.center.permission.service.login.MerchantLoginServiceImpl;
import com.lh.center.reach.api.dubbo.DubboExternalMerchantLoginService;
import com.lh.center.reach.api.dubbo.DubboSystemMerchantIpLimitService;
import com.lh.center.reach.api.external.merchantLogin.beans.ExternalMerchantLoginBean;
import com.lh.center.reach.api.external.merchantLogin.beans.ExternalMerchantLoginResultBean;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 登陆相关
 *
 * @author czy
 * @since 2022-04-07
 */
@RefreshScope
@RestController
@RequestMapping("/api/permission/login")
public class LoginController {

    @Autowired
    private CommonWebAutoConfiguration configuration;

    @DubboReference
    private DubboMerchantInsService merchantInsService;

    @DubboReference
    private DubboMerchantService merchantService;

    @Resource
    private MerchantAdminUserService merchantAdminUserService;

    @DubboReference
    private DubboSystemMerchantIpLimitService dubboSystemMerchantIpLimitService;

    @DubboReference
    private DubboExternalMerchantLoginService dubboExternalMerchantLoginService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private MerchantLoginServiceImpl merchantLoginService;

    @Resource
    private LoginLogService loginLogService;

    @Value("${permission.login.enablePassword}")
    private boolean enablePassword;

    @Value("${spring.profiles.active}")
    private String activeEnv;

    /**
     * 保持心跳接口
     */
    @PostMapping("/keepLive")
    public void keepLive() {
        String headerToken = SessionOperation.getHeaderToken();
        if (StringUtils.isBlank(headerToken)) {
            return;
        }
        //保持心跳
        stringRedisTemplate.expire(RedisPrefix.BACK_ADMIN_USER_TOKEN + headerToken, 30, TimeUnit.MINUTES);
        stringRedisTemplate.expire(RedisPrefix.MERCHANT_ADMIN_USER_TOKEN + headerToken, 30, TimeUnit.MINUTES);
        stringRedisTemplate.expire(RedisPrefix.STORE_ADMIN_USER_TOKEN + headerToken, 30, TimeUnit.MINUTES);
    }

    //SAAS登陆(账号密码)
    @PostMapping("/backstage/login")
    public BackstageSessionUser backstageLoginByPassword(HttpServletRequest request, @RequestBody LoginByPasswordDto dto) {
        return storeLoginLog(request, loginByPassword(MarketingApp.backstage, dto), LogType.backAdminLogin);
    }

    @PostMapping("/backstage/signOut")
    public void backstageSignOut(HttpServletRequest request) {
        signOut(MarketingApp.backstage, request);
    }

    /**
     * 商户端外部授权登录
     */
    @PostMapping("/merchant/externalLogin")
    public MerchantSessionUser merchantExternalLogin(@RequestBody ExternalLoginDto dto) {
        AssertUtil.isEmpty(dto.getConfigUnique(), "缺少配置标识");
        AssertUtil.isNull(dto.getMerchantId(), "缺少商户标识");
        AssertUtil.isEmpty(dto.getCode(), "缺少授权标识");
        ExternalMerchantLoginBean bean = new ExternalMerchantLoginBean();
        bean.setMerchantId(dto.getMerchantId());
        bean.setMerchantConfigUnique(dto.getConfigUnique());
        bean.setCode(dto.getCode());
        ExternalMerchantLoginResultBean result = dubboExternalMerchantLoginService.login(bean);
        String empNo = result.getEmpNo();
        String wxOpenId = result.getWxOpenId();
        //获取登录用户信息
        MerchantAdminUser user = null;
        if (StringUtils.isNotBlank(wxOpenId)) {
            Optional<MerchantAdminUser> mu = merchantAdminUserService.lambdaQuery()
                    .eq(MerchantAdminUser::getMerchantId, dto.getMerchantId())
                    .eq(MerchantAdminUser::getWxOpenId, wxOpenId)
                    .oneOpt();
            if (mu.isPresent()) {
                user = mu.get();
            }
        }
        if (StringUtils.isNotBlank(empNo)) {
            Optional<MerchantAdminUser> mu = merchantAdminUserService.lambdaQuery()
                    .eq(MerchantAdminUser::getMerchantId, dto.getMerchantId())
                    .eq(MerchantAdminUser::getEmpNo, empNo)
                    .oneOpt();
            if (mu.isPresent()) {
                user = mu.get();
            }
        }
        AssertUtil.isNull(user, "登录用户不存在");
        LoginService<?> loginService = LoginServiceFactory.builder(MarketingApp.merchant);
        return merchantLoginService.loginByAdminUser(user);
    }

    //商户登陆(账号密码)
    @PostMapping("/merchant/login")
    public MerchantSessionUser merchantLoginByPassword(HttpServletRequest request, @RequestBody LoginByPasswordDto dto) {
        if (!enablePassword) {
            throw new CommonException("当前系统未开启密码登陆");
        }
        MerchantSessionUser user = storeLoginLog(request, loginByPassword(MarketingApp.merchant, dto), LogType.merchantLogin);

        //检查ip是否限制
//        boolean verify = dubboSystemMerchantIpLimitService.verify(user.getMerchantId(), ServletUtil.getClientIP(SessionOperation.getRequest()));
//        AssertUtil.isTrue(!verify,"IP受限");
        user.setDataAuth(null);
        user.setDataInsIds(null);
        user.setDataEmpIds(null);
        Merchant merchant = merchantService.getById(user.getMerchantId());
        user.setMerchant(merchant);
        return user;
    }

    @PostMapping("/merchant/signOut")
    public void merchantSignOut(HttpServletRequest request) {
        signOut(MarketingApp.merchant, request);
    }

    //商家登陆(账号密码)
    @PostMapping("/store/login")
    public StoreSessionUser storeLoginByPassword(HttpServletRequest request, @RequestBody LoginByPasswordDto dto) {
        StoreSessionUser user = storeLoginLog(request, loginByPassword(MarketingApp.store, dto), LogType.storeLogin);
//        //检查ip是否限制
//        boolean verify = dubboSystemMerchantIpLimitService.verify(user.getMerchantId(), ServletUtil.getClientIP(SessionOperation.getRequest()));
//        AssertUtil.isTrue(!verify,"IP受限");
        return user;
    }

    @PostMapping("/store/signOut")
    public void storeSignOut(HttpServletRequest request) {
        signOut(MarketingApp.store, request);
    }

    //用户登陆(自动注册)
    @PostMapping("/user/login")
    public UserSessionUser userLoginByPassword(@RequestBody LoginByPasswordDto dto) {
        return loginByPassword(MarketingApp.user, dto);
    }

    //厅堂用户C端登陆(账号密码)
    @PostMapping("/tingtang/login")
    public TingtangSessionUser tingtangLoginByPassword(HttpServletRequest request, @RequestBody LoginByPasswordDto dto) {
        /*if(!enablePassword){
            throw new CommonException("当前系统未开启密码登陆");
        }*/
        TingtangSessionUser user = loginByPassword(MarketingApp.tingtang, dto);
        //检查ip是否限制
//        boolean verify = dubboSystemMerchantIpLimitService.verify(user.getMerchantId(), ServletUtil.getClientIP(SessionOperation.getRequest()));
//        AssertUtil.isTrue(!verify,"IP受限");
        return user;
    }

    @PostMapping("/tingtang/signOut")
    public void tingtangSignOut(HttpServletRequest request) {
        signOut(MarketingApp.tingtang, request);
    }

//    //外部系统登陆
//    @PostMapping("/open/openApiInsLogin")
//    public OpenApiLoginVo openApiInsLogin(@RequestBody OpenApiLoginDto dto){
//        if(StringUtils.isEmpty(dto.getAppId()) || StringUtils.isEmpty(dto.getAppSecret())){
//            throw new CommonException("缺少必填参数");
//        }
//        MerchantIns merchant = merchantInsService.getByAppId(dto.getAppId());
//        AssertUtil.isNull(merchant,"商户不存在");
//        DubboSystemMerchantConfigService
//        AssertUtil.isTrue(!dto.getAppSecret().equals(merchant.getAppSecret()),"商户不存在");
//        if(merchant.getStatus().equals(GlobalConstant.ZERO)){
//            throw new CommonException("商户不可用");
//        }
//        OpenApiLoginVo vo = new OpenApiLoginVo();
//        vo.setAccessToken(UUID.randomUUID().toString().replace("-",""));
//        stringRedisTemplate.opsForValue().set(RedisPrefix.OPEN_ACCESS_TOKEN_INS+vo.getAccessToken(), JSONUtil.toJsonStr(merchant),5, TimeUnit.MINUTES);
//        return vo;
//    }

//    //外部系统登陆
//    @PostMapping("/open/openApiLogin")
//    public OpenApiLoginVo openApiLogin(@RequestBody OpenApiLoginDto dto){
//        if(StringUtils.isEmpty(dto.getAppId()) || StringUtils.isEmpty(dto.getAppSecret())){
//            throw new CommonException("缺少必填参数");
//        }
//        Merchant merchant = merchantService.getByAppId(dto.getAppId());
//        AssertUtil.isNull(merchant,"商户不存在");
//        AssertUtil.isTrue(!dto.getAppSecret().equals(merchant.getAppSecret()),"商户不存在");
//        if(merchant.getExpireDate() < System.currentTimeMillis()){
//            throw new CommonException("商户不可用");
//        }
//        if(merchant.getStatus().equals(GlobalConstant.ZERO)){
//            throw new CommonException("商户不可用");
//        }
//
//        OpenApiLoginVo vo = new OpenApiLoginVo();
//        vo.setAccessToken(UUID.randomUUID().toString().replace("-",""));
//        stringRedisTemplate.opsForValue().set(RedisPrefix.OPEN_ACCESS_TOKEN+vo.getAccessToken(), JSONUtil.toJsonStr(merchant),5, TimeUnit.MINUTES);
//     return vo;
//    }

    private <T> T storeLoginLog(HttpServletRequest request, SessionUser user, LogType type) {

        if (StringUtils.isNotBlank(activeEnv) && "poc".equals(activeEnv)) {
            // poc环境直接返回，不存日志。
            return (T) user;
        }

        Long userId = user.getUserId();
        String userName = "";
        String account = "";
        Long insId = null;
        if (LogType.backAdminLogin.remark.equals(type.remark)) {
            BackstageSessionUser target = (BackstageSessionUser) user;
            userName = target.getUsername();
            account = target.getUsername();
        } else if (LogType.merchantLogin.remark.equals(type.remark)) {
            MerchantSessionUser target = (MerchantSessionUser) user;
            userName = target.getUsername();
            account = target.getUsername();
            insId = target.getInsId();
        } else if (LogType.storeLogin.remark.equals(type.remark)) {
            StoreSessionUser target = (StoreSessionUser) user;
            userName = target.getUserName();
            account = target.getUserName();
        }

        if (org.apache.commons.lang.StringUtils.isBlank(userName) && org.apache.commons.lang.StringUtils.isBlank(account)) {
            throw new CommonException("非法登录");
        }

        // 获取merchant_id
        Long merchantId = user.getMerchantId();

        // 设置IP
        String clientIP = ServletUtil.getClientIP(request);

        // IP归属地
        String ipBelong = IpBelongWithinJuheUtil.getIpBelongWithinJuhe(clientIP);

        storeLog(userId, account, userName, "account", String.valueOf(type), type.remark, clientIP, ipBelong, merchantId, insId);

        return (T) user;
    }

    private void storeLog(Long userId, String account, String userName, String loginType, String type, String typeRemark, String ip, String ipBelong, Long merchantId, Long insId) {
        LoginLogEntity log = new LoginLogEntity();
        log.setUserId(userId);
        log.setAccount(account);
        log.setUserName(userName);
        log.setLoginType(loginType);
        log.setType(type);
        log.setTypeRemark(typeRemark);
        log.setIp(ip);
        log.setIpBelong(ipBelong);
        log.setMerchantId(merchantId);
        log.setInsId(insId);
        loginLogService.saveOrUpdate(log);
    }

    private <T> T loginByPassword(MarketingApp app, LoginByPasswordDto dto) {
        LoginService<?> loginService = LoginServiceFactory.builder(app);
        return (T) loginService.loginByPassword(dto.getAccount(), dto.getPassword(), dto.getVerifyText(), dto.getVerifyToken());
    }

    private void signOut(MarketingApp app, HttpServletRequest request) {
        LoginService<?> loginService = LoginServiceFactory.builder(app);
        String token = request.getHeader(configuration.getTokenName());
        loginService.signOut(token);
    }
}

